﻿using System;
using GeoAPI.Geometries;

namespace NetTopologySuite.LinearReferencing
{
	public class LocationIndexedLine
	{
		public LocationIndexedLine(IGeometry linearGeom)
		{
			if (!LocationIndexedLine.CheckGeometryType(linearGeom))
			{
				throw new ArgumentException("Input geometry must be linear", "linearGeom");
			}
			this._linearGeom = linearGeom;
		}

		private static bool CheckGeometryType(IGeometry linearGeometry)
		{
			return linearGeometry is ILineString || linearGeometry is IMultiLineString;
		}

		public Coordinate ExtractPoint(LinearLocation index)
		{
			return index.GetCoordinate(this._linearGeom);
		}

		public Coordinate ExtractPoint(LinearLocation index, double offsetDistance)
		{
			LinearLocation linearLocation = index.ToLowest(this._linearGeom);
			return linearLocation.GetSegment(this._linearGeom).PointAlongOffset(linearLocation.SegmentFraction, offsetDistance);
		}

		public Coordinate ExtractPoint(double index, double offsetDistance)
		{
			LinearLocation location = LengthLocationMap.GetLocation(this._linearGeom, index);
			return location.GetSegment(this._linearGeom).PointAlongOffset(location.SegmentFraction, offsetDistance);
		}

		public IGeometry ExtractLine(LinearLocation startIndex, LinearLocation endIndex)
		{
			return ExtractLineByLocation.Extract(this._linearGeom, startIndex, endIndex);
		}

		public LinearLocation IndexOf(Coordinate pt)
		{
			return LocationIndexOfPoint.IndexOf(this._linearGeom, pt);
		}

		public LinearLocation[] IndicesOf(IGeometry subLine)
		{
			return LocationIndexOfLine.IndicesOf(this._linearGeom, subLine);
		}

		public LinearLocation IndexOfAfter(Coordinate pt, LinearLocation minIndex)
		{
			return LocationIndexOfPoint.IndexOfAfter(this._linearGeom, pt, minIndex);
		}

		public LinearLocation Project(Coordinate pt)
		{
			return LocationIndexOfPoint.IndexOf(this._linearGeom, pt);
		}

		public LinearLocation StartIndex
		{
			get
			{
				return new LinearLocation();
			}
		}

		public LinearLocation EndIndex
		{
			get
			{
				return LinearLocation.GetEndLocation(this._linearGeom);
			}
		}

		public bool IsValidIndex(LinearLocation index)
		{
			return index.IsValid(this._linearGeom);
		}

		public LinearLocation ClampIndex(LinearLocation index)
		{
			LinearLocation linearLocation = (LinearLocation)index.Clone();
			linearLocation.Clamp(this._linearGeom);
			return linearLocation;
		}

		private readonly IGeometry _linearGeom;
	}
}
